package org.juiceshop.gm;

import java.io.File;
import java.util.List;

import org.codehaus.groovy.control.CompilerConfiguration;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.GroovySystem;
import groovy.lang.MetaMethod;
import groovy.lang.MetaObjectProtocol;
import groovy.lang.MetaProperty;
import groovy.lang.Script;


public class MusicShell extends GroovyShell {

	
	public MusicShell() {
		super(createCompilerConfiguration());	
	}
	
	public static void main(String[] args) {		
		String scriptFileName = args[0];
		if (!scriptFileName.endsWith(".groovy")) {
			System.err.println(scriptFileName+" is not a Groovy file");
			return;
		}
		File scriptFile = new File(args[0]);
		MusicShell shell = new MusicShell();
		String[] scriptArgs = new String[args.length-1];
		System.arraycopy(args, 1, scriptArgs, 0, scriptArgs.length);
		shell.setVariable("args", scriptArgs);
		try {
			shell.evaluate(scriptFile);		
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		System.exit(0);
	}
	
	private static CompilerConfiguration createCompilerConfiguration() {
		CompilerConfiguration cc = new CompilerConfiguration();
		cc.setScriptBaseClass(XMusicScript.class.getName());
		return cc;
	}
	
	
	public static abstract class XMusicScript extends Script {
		
		private Music _music = new Music();
		private MetaObjectProtocol _musicMop = GroovySystem.getMetaClassRegistry().getMetaClass(Music.class);
		
		public XMusicScript() {
			super();
		}

		public XMusicScript(Binding binding) {
			super(binding);
		}

		@Override
		public Object getProperty(String property) {
			if (property.equals("music")) {
				return _music;
			}
			MetaProperty mp = _musicMop.hasProperty(_music,property);
			if (mp!=null) return mp.getProperty(_music);
			Object result = _music.tryGet(property);
			if (result!=null) return result;
			return super.getProperty(property);
		}
		
		@Override
		public Object invokeMethod(String name, Object args) {
			Object[] argsArray = (Object[])args;
			List<?> methods = _musicMop.respondsTo(_music, name, argsArray);
			if (methods!=null && methods.size()>0) {
				MetaMethod mm = (MetaMethod)methods.get(0);
				if (mm.isVargsMethod(argsArray)) {
					return mm.invoke(_music, new Object[]{argsArray});
				} else {
					return mm.invoke(_music, (Object[])args);
				}
			}
			Object result = _music.tryCall(name, args);
			if (result!=null) return result;
			return super.invokeMethod(name, args);
		}
	}
}
